#include "lib/print.h"
#include "lib/str.h"
#include "lib/lock.h"
#include "mem/pmem.h"
#include "mem/vmem.h"
#include "mem/mmap.h"
#include "memlayout.h"

// 包装 mmap_region_t 用于仓库组织
typedef struct mmap_region_node {
    mmap_region_t mmap;
    struct mmap_region_node* next;
} mmap_region_node_t;

#define N_MMAP 256

// mmap_region_node_t 仓库(单向链表) + 指向链表头节点的指针 + 保护仓库的锁
static mmap_region_node_t list_mmap_region_node[N_MMAP];
static mmap_region_node_t* list_head;
static spinlock_t list_lk;

// 初始化上述三个数据结构
void mmap_init() {   
    // 初始化仓库，构建链表结构
    for (int i = 0; i < N_MMAP; i++) {
        // 初始化每个节点的基本属性
        list_mmap_region_node[i].mmap.begin = MMAP_BEGIN;
        list_mmap_region_node[i].mmap.npages = 0;

        // 设置下一个节点，最后一个节点的 next 设为 NULL
        list_mmap_region_node[i].next = (i < N_MMAP - 1) ? &list_mmap_region_node[i + 1] : NULL;
    }

    // 初始化头结点的指针，指向链表的起始节点
    list_head = &list_mmap_region_node[0];

    // 初始化自旋锁
    spinlock_init(&list_lk, "mmap_list_lock");
}


// 从仓库申请一个 mmap_region_t
// 若申请失败则 panic
// 注意: list_head 保留, 不会被申请出去
mmap_region_t* mmap_region_alloc() {   
    spinlock_acquire(&list_lk); // 获取锁

    if (!list_head->next) { // 检查是否有可用节点
        spinlock_release(&list_lk);
        printf("mmap_region_alloc: No available mmap_region_node_t.\n");
        return NULL; // 返回 NULL 而不是直接 panic
    }

    // 分配链表中的第一个可用节点
    mmap_region_node_t *alloc = list_head->next;
    list_head->next = alloc->next; // 更新链表头的 next 指针

    spinlock_release(&list_lk); // 释放锁

    // 返回合法节点的 mmap_region_t 地址
    return &alloc->mmap;
}

// 向仓库归还一个 mmap_region_t
void mmap_region_free(mmap_region_t* mmap) {   
    // 检查输入参数的合法性
    if (!mmap) {
        printf("mmap_region_free: Invalid mmap_region_t pointer.\n");
        return; // 直接返回，避免空指针解引用
    }

    spinlock_acquire(&list_lk); // 获取锁

    // 计算出对应节点的索引
    uint64 base_addr = (uint64)&list_mmap_region_node->mmap;
    uint64 offset = (uint64)mmap - base_addr;
    int id = offset / sizeof(list_mmap_region_node[0]);

    // 检查索引是否在合法范围内
    if (id < 0 || id >= N_MMAP) {
        spinlock_release(&list_lk);
        printf("mmap_region_free: Invalid mmap_region_t index %d.\n", id);
        return;
    }

    // 将节点插入到链表头后面
    list_mmap_region_node[id].next = list_head->next;
    list_head->next = &list_mmap_region_node[id];

    spinlock_release(&list_lk); // 释放锁
}

// 输出仓库里可用的 mmap_region_node_t
// for debug
void mmap_show_mmaplist()
{
    spinlock_acquire(&list_lk);
    
    mmap_region_node_t* tmp = list_head;
    int node = 1, index = 0;
    while (tmp)
    {
        index = tmp - list_head;
        printf("node %d index = %d\n", node++, index);
        tmp = tmp->next;
    }

    spinlock_release(&list_lk);
}